<style lang="scss" scoped></style>
<template>
    <div ref="display" class="display w-100p" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0)"></div>
</template>
<script>
    const Sass = window.Sass
    import Vue from 'vue'
    import randomStr from './_random_str.js' // 生成随机数给id
    import { debounce } from 'lodash'

    let reload = debounce(function(cb) {
        cb && cb()
    }, 600)

    export default {
        name: 'ui-display',
        props: {
            code: {
                type: String,
                default: ''
            },
            comp: {
                type: [Function, Object]
            },
        },
        data() {
            return {
                html: '',
                js: '',
                css: '',
                id: randomStr(),
                loading: false
            }
        },
        mounted() {
            this.renderCode()
        },
        methods: {
            // 获取vue代码并拆分为各个片段
            getSource(source, type) {
                const regex = new RegExp(`<${ type }[^>]*>`)
                let openingTag = source.match(regex)

                if (!openingTag) return ''
                else openingTag = openingTag[0]

                return source.slice(source.indexOf(openingTag) + openingTag.length, source.lastIndexOf(`</${ type }>`))
            },
            // 将片段装入data
            splitCode() {
                const script = this.getSource(this.code, 'script').replace(/export default/, 'return ')
                const js = this.getSource(this.code, 'js').replace(/export default/, 'return ')
                const style = this.getSource(this.code, 'style')
                // const template = '<div id="displayApp">' + this.getSource(this.code, 'template') + '</div>'
                const template = this.getSource(this.code, 'template')

                this.js = script || js || 'return {}'
                this.css = style
                this.html = template
            },
            // 渲染页面
            renderCode() {
                this.splitCode()
                // html
                if (this.html !== '') {
                    const parseStrToFunc = new Function(this.js)()

                    parseStrToFunc.template = this.html
                    const Component = Vue.extend(parseStrToFunc)
                    this.component = new Component({
                        propsData: {
                            comp: this.comp
                        }
                    }).$mount()

                    this.$refs.display.appendChild(this.component.$el)
                }
                // css
                if (this.css !== '') {
                    const style = document.createElement('style')
                    style.type = 'text/css'
                    style.id = this.id
                    // 解析scss
                    let css = this.css.replace(/\n|\r|\t/g, '').replace(/\s+/g, "")
                    Sass.compile(css, { indentedSyntax: true, comments: false, style: Sass.style.compressed }, result => {
                        style.innerHTML = result.text
                        document.getElementsByTagName('head')[0].appendChild(style)
                    });

                }
            },
            // 销毁方法
            destroyCode() {
                const $target = document.getElementById(this.id)
                if ($target) $target.parentNode.removeChild($target)

                if (this.component) {
                    this.$refs.display.removeChild(this.component.$el)
                    this.component.$destroy()
                    this.component = null
                }
            },
        },
        watch: {
            // 实时监控传入的vue代码, 并执行渲染
            code() {
                // 先销毁上一次的
                this.destroyCode()
                this.loading = true
                // 再撸一发
                reload(() => {
                    this.renderCode()
                    this.loading = false
                })

            },
            comp() {
                this.destroyCode()
                this.renderCode()
            }
        },
        beforeDestroy() {
            this.destroyCode()
        }
    }
</script>
